package com.rongzhe.house.pay;

import com.rongzhe.house.common.utils.DateUtil;
import com.rongzhe.house.common.utils.OkHttpUtil;
import com.rongzhe.house.common.utils.XmlUtils;
import com.rongzhe.house.pay.entity.WeixinOrder;
import com.rongzhe.house.pay.entity.WeixinPayPost;
import com.rongzhe.house.security.MD5Util;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanMap;

import java.io.IOException;
import java.text.ParseException;
import java.util.*;

/**
 * Created by hggxg on 2017/11/15.
 */
public class WxpayServiceImpl implements WxpayService {


    @Autowired
    private WeiXinPayConfig weixinpayConfig;

    @Override
    public Map<String, String> precreate(WeixinOrder weixinOrder) {
        if (weixinOrder == null) {
            return null;
        }
        weixinOrder.setAppid(this.weixinpayConfig.getAppid());
        weixinOrder.setMch_id(this.weixinpayConfig.getMch_id());
        weixinOrder.setNotify_url(this.weixinpayConfig.getNotify_url());
        weixinOrder.setTrade_type(this.weixinpayConfig.getTrade_type());
        weixinOrder.setNonce_str(RandomStringUtils.randomAlphanumeric(20));

        Map<String, String> map = new HashMap();
        BeanMap beanMap = BeanMap.create(weixinOrder);
        for (Object key : beanMap.keySet()) {
            if (null != beanMap.get(key)) {
                map.put(key + "", beanMap.get(key).toString());
            }
        }
        weixinOrder.setSign(createSign(map));

        Map<String, String> data = null;
        String url = this.weixinpayConfig.getPrecreate_Url();
        MediaType type = MediaType.parse("text/xml");
        RequestBody requestBody = RequestBody.create(type, toXml(weixinOrder));


        Request request = new Request.Builder().url(url).post(requestBody).build();
        try {
            Response response = OkHttpUtil.execute(request);
            if (response.isSuccessful()) {
                data = XmlUtils.xmlBody2map(response.body().string(), "xml");
                if (validateSign(data)) {
                    Map<String, String> mapPay = new HashMap();
                    if (weixinOrder.getTrade_type().equals("APP")) {
                        mapPay.put("appid", this.weixinpayConfig.getAppid());
                        mapPay.put("partnerid", this.weixinpayConfig.getMch_id());
                        mapPay.put("prepayid", data.get("prepay_id"));
                        mapPay.put("package", "Sign=WXPay");
                        mapPay.put("noncestr", RandomStringUtils.randomAlphanumeric(20));
                        mapPay.put("timestamp", new Date().getTime() / 1000L + "");
                        mapPay.put("sign", createSign(mapPay));
                    } else if (weixinOrder.getTrade_type().equals("JSAPI")) {
                        mapPay.put("appId", this.weixinpayConfig.getAppid());
                        mapPay.put("package", "prepay_id=" + data.get("prepay_id"));
                        mapPay.put("signType", "MD5");
                        mapPay.put("nonceStr", RandomStringUtils.randomAlphanumeric(20));
                        mapPay.put("timeStamp", new Date().getTime() / 1000L + "");
                        mapPay.put("sign", createSign(mapPay));
                    }
                    return null;
                }
                data = null;
            } else {
                throw new IOException("Unexpected code " + response);
            }
        } catch (Exception e) {
            return null;
        }
        return data;
    }

    @Override
    public WeixinPayPost checkSign(Map<String, String> paramMap) {

        if (validateSign(paramMap)) {
            if (paramMap.get("result_code").equals("SUCCESS")) {


                String dateParttern = "yyyyMMddHHmmss";
                WeixinPayPost weixinPayPost = new WeixinPayPost();
                weixinPayPost.setOutTradeNo(paramMap.get("out_trade_no"));
                weixinPayPost.setTransactionId(paramMap.get("transaction_id"));
                weixinPayPost.setCashFee(paramMap.get("cash_fee"));
                try {
                    weixinPayPost.setTimeEnd(DateUtil.stringToDate(dateParttern, (String) paramMap.get("time_end")));
                } catch (ParseException e) {
                    e.printStackTrace();
                }

                return weixinPayPost;
            }
        }
        return null;
    }


    private String toXml(WeixinOrder orderVO) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        BeanMap beanMap = BeanMap.create(orderVO);
        for (Object key : beanMap.keySet()) {
            if (null != beanMap.get(key)) {
                sb.append("<" + key + ">");
                sb.append(beanMap.get(key));
                sb.append("</" + key + ">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }

    private String toXml(Map<String, String> map) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        for (Object key : map.keySet()) {
            if (null != map.get(key)) {
                sb.append("<" + key + ">");
                sb.append(map.get(key));
                sb.append("</" + key + ">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }


    private String createSign(Map<String, String> map) {
        List<String> list = new ArrayList(map.keySet());
        Collections.sort(list);
        String keyValueStr = "";
        for (String key : list) {
            if ((null != map.get(key)) && (!"sign".equals(key))) {
                keyValueStr = keyValueStr + key + "=" + (String) map.get(key) + "&";
            }
        }
        keyValueStr = keyValueStr + "key=" + this.weixinpayConfig.getKey();
        return MD5Util.getMD5(keyValueStr).toUpperCase();
    }


    private boolean validateSign(Map<String, String> map) {
        String signRetrun = (String) map.get("sign");

        String sign = createSign(map);
        if (sign.equals(signRetrun)) {
            return true;
        }
        return false;
    }
}
